home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0050_Delphi Detecting CPU Type.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-11-24  |  5.9 KB  |  184 lines

  1.  
  2. {Here is a Delphi unit to detect the CPU type, modified from Intel's
  3. code. Use should be fairly obvious.  If not, send me email, and I can
  4. send you an example program.  Because Delphi's assembler is 16-bit,
  5. the code looks a little wierd.  Try using a 32-bit disassembler to see
  6. the 32-bit instructions (or read the comments). }
  7.  
  8. unit CpuId;
  9.  
  10. { This code comes from Intel, and has been modified for Delphi's
  11.   inline assembler.  Since Intel made the original code freely
  12.   available, I am making my changes freely available.
  13.  
  14.   Share and enjoy!
  15.  
  16.   Ray Lischner
  17.   Tempest Software
  18.   6/18/95
  19. }
  20.  
  21. interface
  22.  
  23. type
  24.   { All the types currently known.  As new types are created,
  25.     add suitable names, and extend the case statement in
  26.     CpuTypeString.
  27.   }
  28.   TCpuType = (cpu8086, cpu80286, cpu386, cpu486, cpuPentium);
  29.  
  30. { Return the type of the current CPU }
  31. function CpuType: TCpuType;
  32.  
  33. { Return the type as a short string }
  34. function CpuTypeString: String;
  35.  
  36. implementation
  37.  
  38. uses SysUtils;
  39.  
  40. function CpuType: TCpuType; assembler;
  41. asm
  42.   push DS
  43.  
  44. { First check for an 8086 CPU }
  45. { Bits 12-15 of the FLAGS register are always set on the }
  46. { 8086 processor. }
  47.   pushf                       { save EFLAGS }
  48.   pop        bx                  { store EFLAGS in BX }
  49.   mov        ax,0fffh            { clear bits 12-15 }
  50.   and        ax,bx               { in EFLAGS }
  51.   push    ax                   { store new EFLAGS value on stack }
  52.   popf                        { replace current EFLAGS value }
  53.   pushf                       { set new EFLAGS }
  54.   pop        ax                  { store new EFLAGS in AX }
  55.   and        ax,0f000h        { if bits 12-15 are set, then CPU }
  56.   cmp        ax,0f000h        { is an 8086/8088 }
  57.   mov     ax, cpu8086     { turn on 8086/8088 flag }
  58.   je        @@End_CpuType
  59.  
  60.   { 80286 CPU check }
  61.   { Bits 12-15 of the FLAGS register are always clear on the }
  62.   { 80286 processor. }
  63.   or        bx,0f000h        { try to set bits 12-15 }
  64.   push     bx
  65.   popf
  66.   pushf
  67.   pop        ax
  68.   and        ax,0f000h          { if bits 12-15 are cleared, CPU=80286 }
  69.   mov     ax, cpu80286      { turn on 80286 flag }
  70.   jz        @@End_CpuType
  71.  
  72.   { To test for 386 or better, we need to use 32 bit instructions,
  73.     but the 16-bit Delphi assembler does not recognize the 32 bit
  74. opcodes
  75.     or operands.  Instead, use the 66H operand size prefix to change
  76.     each instruction to its 32-bit equivalent. For 32-bit immediate
  77.     operands, we also need to store the high word of the operand
  78. immediately
  79.     following the instruction.  The 32-bit instruction is shown in a
  80. comment
  81.     after the 66H instruction.
  82.   }
  83.  
  84.   { i386 CPU check }
  85.   { The AC bit, bit #18, is a new bit introduced in the EFLAGS }
  86.   { register on the i486 DX CPU to generate alignment faults. }
  87.   { This bit can not be set on the i386 CPU. }
  88.  
  89.   db 66h                    { pushfd }
  90.   pushf
  91.   db 66h                    { pop eax }
  92.   pop    ax                        { get original EFLAGS }
  93.   db 66h                    { mov ecx, eax }
  94.   mov    cx,ax                     { save original EFLAGS }
  95.   db 66h                    { xor eax,40000h }
  96.   xor    ax,0h                    { flip AC bit in EFLAGS }
  97.   dw 0004h
  98.   db 66h                    { push eax }
  99.   push ax                      { save for EFLAGS }
  100.   db 66h                    { popfd }
  101.   popf                          { copy to EFLAGS }
  102.   db 66h                    { pushfd }
  103.   pushf                          { push EFLAGS }
  104.   db 66h                    { pop eax }
  105.   pop    ax                        { get new EFLAGS value }
  106.   db 66h                    { xor eax,ecx }
  107.   xor    ax,cx                     { can't toggle AC bit, CPU=Intel386 }
  108.   mov ax, cpu386            { turn on 386 flag }
  109.   je @@End_CpuType
  110.  
  111. { i486 DX CPU / i487 SX MCP and i486 SX CPU checking }
  112. { Checking for ability to set/clear ID flag (Bit 21) in EFLAGS }
  113. { which indicates the presence of a processor }
  114. { with the ability to use the CPUID instruction. }
  115.   db 66h                    { pushfd }
  116.   pushf                          { push original EFLAGS }
  117.   db 66h                    { pop eax }
  118.   pop    ax                        { get original EFLAGS in eax }
  119.   db 66h                    { mov ecx, eax }
  120.   mov    cx,ax                     { save original EFLAGS in ecx }
  121.   db 66h                    { xor eax,200000h }
  122.   xor    ax,0h                    { flip ID bit in EFLAGS }
  123.   dw 0020h
  124.   db 66h                    { push eax }
  125.   push ax                      { save for EFLAGS }
  126.   db 66h                    { popfd }
  127.   popf                          { copy to EFLAGS }
  128.   db 66h                    { pushfd }
  129.   pushf                     { push EFLAGS }
  130.   db 66h                    { pop eax }
  131.   pop    ax                        { get new EFLAGS value }
  132.   db 66h                    { xor eax, ecx }
  133.   xor ax, cx
  134.   mov ax, cpu486            { turn on i486 flag }
  135.   je @@End_CpuType           { if ID bit cannot be changed, CPU=486
  136. }
  137.                                  { without CPUID instruction functionality }
  138.  
  139. { Execute CPUID instruction to determine vendor, family, }
  140. { model and stepping.  The use of the CPUID instruction used }
  141. { in this program can be used for B0 and later steppings }
  142. { of the P5 processor. }
  143.    db 66h                  { mov eax, 1 }
  144.     mov ax, 1                  { set up for CPUID instruction }
  145.    dw 0
  146.    db 66h                  { cpuid }
  147.     db    0Fh                   { Hardcoded opcode for CPUID
  148. instruction }
  149.     db    0a2h
  150.    db 66h                  { and eax, 0F00H }
  151.     and ax, 0F00H             { mask everything but family }
  152.    dw 0
  153.    db 66h                  { shr eax, 8 }
  154.     shr ax, 8               { shift the cpu type down to the low byte }
  155.    sub ax, 1               { subtract 1 to map to TCpuType }
  156.  
  157. @@End_CpuType:
  158.    pop ds
  159. end;
  160.  
  161. function CpuTypeString: String;
  162. var
  163.   kind: TCpuType;
  164. begin
  165.   kind := CpuType;
  166.   case kind of
  167.   cpu8086:
  168.     Result := '8086';
  169.   cpu80286:
  170.     Result := '80286';
  171.   cpu386:
  172.     Result := '386';
  173.   cpu486:
  174.     Result := '486';
  175.   cpuPentium:
  176.     Result := 'Pentium';
  177.   else
  178.     { Try to be flexible for future cpu types, e.g., P6. }
  179.     Result := Format('P%d', [Ord(kind)]);
  180.   end;
  181. end;
  182.  
  183. end.
  184.